/*

 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *

hipdmxctl.h - (c) 2012 - Rowan Maclachlan (hippy - dmxout@gmail.com).

*/

#ifndef HIPDMXCTL_INCLUDED
#define HIPDMXCTL_INCLUDED

// -----  Code switching

// enable shared memory communication functions
#define HIP_SHM

// align frame breaks across universes
#define BREAK_SYNC

// used to exclude some intensive debugging info in loops
#define  DEBUG   

#ifdef DEBUG
// #define  DEBUG_PROFILE        // debugging information on function times
#endif

// control realtime scheduling
// #define  TX_PRIO_RT  // control scheduling



// ----- Constants
// size constants
#ifdef BREAK_SYNC
#define PREAMBLE_SIZE                3	        // sync delay + break and MAB operations (tx)
#else
#define PREAMBLE_SIZE                2	        // Break and MAB operations (tx)
#endif

#define MAX_DMX_FRAME_SIZE    513	    // START code + 512 slots


// number of xuarts used
#define XLR_FIRST   0       
#define XLR_LAST    3       // 4 XUARTS used


// tx modes
#define MODE_DISABLE  0  // disable this port
#define MODE_TX            1   // xlr always sending dmx
#define MODE_TX_RDM  2  // tx an DMX/RDM frame, 
                                             // then expect RDM reply within 2.1ms, 
                                             // if no reply, continue sending dmx.

// rx states
#define RX_STATE_OFF     0   // rx for this engine is disabled and ignored
#define RX_STATE_WFB    1   // wait for break
#define RX_STATE_WFI     2   // wait for idle
#define RX_STATE_RXDATA   3  //  getting the data
#define RX_STATE_WRITE_DATA  4 // writing the data to a hipnet universe

#define RX_BREAKTIME_THRESHOLD  11   // 44us
#define RX_IDLETIME_THRESHOLD  2  // 8us

#define RDM_TIMEOUT -36  // returned if an expected RDM frame didn't arive 
#define RDM_TIMEOUT_TIME  2100  // time in microseconds to wait for an RDM reply




// ----- Macros 
#ifndef TEMP_FAILURE_RETRY
# define TEMP_FAILURE_RETRY(expression) \
  (__extension__                                                              \
    ({ long int __result;                                                     \
       do __result = (long int) (expression);                                 \
       while (__result == -1L && errno == EINTR);                             \
       __result; }))
#endif

#define bit_get(p,m) ((p) & (m))
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))
#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))
#define BIT(x) (0x01 << (x))
#define LONGBIT(x) ((unsigned long)0x00000001 << (x)


// ----- Structures


// frame buffer used to TX to the wire (XUART)
typedef struct tx_frame_t {
    int length;		// number of bytes to send, including preamble, START code and data (max 515)
    int frame_time;	// time required to send frame in uS
    uint16_t  data[PREAMBLE_SIZE+MAX_DMX_FRAME_SIZE]; // preamble (2) + frame data (513 or less)
} tx_frame_t;


// the XLR port structure contains the settings and tx buffers
// for one XUART
typedef struct xlr_port_t {
    int fd;// = -1;     // xuart file descriptor 
    int mode; // = #MODE_TX;  
    // frame timing
    int break_time;// = 176;    // == 176us  
    int mab_time;// = 12;       // == 12us
    int inter_frame_delay;     // == 176us to wait between packets    
    // --- dmx/rdm buffer to transmit
    uint8_t 	dmx_tx_buf[MAX_DMX_FRAME_SIZE];  	// dmx/rdm slots to send to wire
    int dmx_tx_buf_length;		// number of slots to send, including START code
    struct sockaddr_in    xuart_sockAddr;    // xuart socket address
    tx_frame_t	tx_frame_buf;		// buffer used to tx to the wire
} xlr_port_t;


// state information for an rx engine
typedef struct rx_state_t {
  int state;    // RX_STATE_*
  int frame_time;
  int break_time;
  int idle_time; 
  int data_length;
  uint8_t data[MAX_DMX_FRAME_SIZE];
} rx_state_t;



// ----- Options!
int opt_debug = 0;        // debugging mode
int opt_debugv = 0;      // verbose
int opt_debugx = 0;      // xuart RX opcode debugging
int opt_debug_log = 0;
int opt_background = 0;
int opt_shm = 0;
int opt_2node = 0;
int opt_tx = 0;
int opt_rx = 0;


// ---- Array of XLR ports - xlr
xlr_port_t    xlr[XLR_LAST+1];    

// an array of rx engines states
rx_state_t  rx_eng[XLR_LAST+1];


// thread id's & stuff
pthread_t   xlr_tx_thread;
pthread_t   xlr_rx_thread;

pthread_mutex_t     xlr_lock;


#ifdef HIP_SHM
// shm format for the IPC used to talk with a controller
typedef struct shm_block_t {
  uint32_t   seq;  // incremented for every operation, indicates a change                       
  uint8_t ack;
  hipnet_data_t   data; // hipnet data frame
} shm_block_t;

shm_block_t *tx_shm[XLR_LAST+1]; 
shm_block_t *rx_shm[XLR_LAST+1]; 

int tx_shmid[XLR_LAST+1];
key_t  tx_shmkey[XLR_LAST+1];

int rx_shmid[XLR_LAST+1];
key_t  rx_shmkey[XLR_LAST+1];
#endif


#ifdef TX_PRIO_RT
// scheduling stuff 
int sched_pmin, sched_pmax;
struct sched_param sched_initial_sp;
int sched_initial_policy;
struct sched_param sched_sp;
#endif


// logging stuff
FILE *logfile;



static inline int hipnet_socket_write(unsigned short *data, int size);
static inline int hipnet_shm_write(int xlr_num, unsigned short *data, int size);
int process_packet(hipnet_data_t *packet);



#endif
